%{
#include <stdio.h>
#include "wuji.h"
#define YYDEBUG 1
%}
%union {
    char                *identifier;
    ParameterList       *parameter_list;
    ArgumentList        *argument_list;
    Expression          *expression;
    ExpressionList      *expression_list;
    Statement           *statement;
    StatementList       *statement_list;
    Block               *block;
    Elsif               *elsif;
	AssignmentOperator	assignment_operator;
    IdentifierList      *identifier_list;
}
%token <expression>     INT_LITERAL
%token <expression>     DOUBLE_LITERAL
%token <expression>     STRING_LITERAL
%token <identifier>     IDENTIFIER
%token FUNCTION IF ELSIF ELSE WHILE RETURN_T GLOBAL_T BREAK CONTINUE NULL_T
        TRUE_T FALSE_T FOREACH CLOSURE TRY CATCH FINALLY THROW FINAL 
		LP RP LB RB COLON LC RC COMMA DOT LOGICAL_AND LOGICAL_OR ASSIGN
        EQ NE GT GE LT LE ADD SUB MUL DIV MOD EXCLAMATION 
		ADD_ASSIGN_T SUB_ASSIGN_T MUL_ASSIGN_T DIV_ASSIGN_T MOD_ASSIGN_T INCREMENT DECREMENT
%type   <parameter_list> parameter_list
%type   <argument_list> argument_list
%type   <expression> expression
        assignment_expression logical_and_expression logical_or_expression
        equality_expression relational_expression
        additive_expression multiplicative_expression
        unary_expression postfix_expression primary_expression array_literal
		closure_definition
%type   <expression_list> expression_list
%type   <statement> statement global_statement
        if_statement while_statement foreach_statement
        return_statement break_statement continue_statement
		throw_statement
%type   <statement_list> statement_list
%type   <block> block
%type   <elsif> elsif elsif_list
%type	<assignment_operator> assignment_operator
%type   <identifier_list> identifier_list
%%
translation_unit
        : definition_or_statement
        | translation_unit definition_or_statement
        ;
definition_or_statement
        : function_definition
        | statement
        {
            WJ_Interpreter *inter = wj_get_current_interpreter();

            inter->statement_list
                = wj_chain_statement_list(inter->statement_list, $1);
        }
        ;
function_definition
        : FUNCTION IDENTIFIER LP parameter_list RP block
        {
			/* 函数：函数名（参数）{...} */
            wj_function_define($2, $4, $6);
        }
        | FUNCTION IDENTIFIER LP RP block
        {
			/* 函数：函数名（）{...} */
            wj_function_define($2, NULL, $5);
        }
        ;
parameter_list
        : IDENTIFIER
        {
            $$ = wj_create_parameter($1);
        }
        | parameter_list COMMA IDENTIFIER
        {
            $$ = wj_chain_parameter($1, $3);
        }
        ;
argument_list
        : assignment_expression
        {
            $$ = wj_create_argument_list($1);
        }
        | argument_list COMMA assignment_expression
        {
            $$ = wj_chain_argument_list($1, $3);
        }
        ;
statement_list
        : statement
        {
            $$ = wj_create_statement_list($1);
        }
        | statement_list statement
        {
            $$ = wj_chain_statement_list($1, $2);
        }
        ;
expression
        : assignment_expression
        | expression COMMA assignment_expression
        {
            $$ = wj_create_comma_expression($1, $3);
        }
        ;
assignment_expression
		: logical_or_expression
		| postfix_expression assignment_operator assignment_expression
		{
			$$ = wj_create_assign_expression(WJ_FALSE, $1, $2, $3);
		}
		| FINAL postfix_expression assignment_operator assignment_expression
		{
			$$ = wj_create_assign_expression(WJ_TRUE, $2, $3, $4);
		}
		;
assignment_operator
		: ASSIGN
		{
			$$ = NORMAL_ASSIGN;
		}
		| ADD_ASSIGN_T
		{
			$$ = ADD_ASSIGN;
		}
		| SUB_ASSIGN_T
		{
			$$ = SUB_ASSIGN;
		}
		| MUL_ASSIGN_T
		{
			$$ = MUL_ASSIGN;
		}
		| DIV_ASSIGN_T
		{
			$$ = DIV_ASSIGN;
		}
		| MOD_ASSIGN_T
		{
			$$ = MOD_ASSIGN;
		}
		;
logical_or_expression
        : logical_and_expression
        | logical_or_expression LOGICAL_OR logical_and_expression
        {
            $$ = wj_create_binary_expression(LOGICAL_OR_EXPRESSION, $1, $3);
        }
        ;
logical_and_expression
        : equality_expression
        | logical_and_expression LOGICAL_AND equality_expression
        {
            $$ = wj_create_binary_expression(LOGICAL_AND_EXPRESSION, $1, $3);
        }
        ;
equality_expression
        : relational_expression
        | equality_expression EQ relational_expression
        {
            $$ = wj_create_binary_expression(EQ_EXPRESSION, $1, $3);
        }
        | equality_expression NE relational_expression
        {
            $$ = wj_create_binary_expression(NE_EXPRESSION, $1, $3);
        }
        ;
relational_expression
        : additive_expression
        | relational_expression GT additive_expression
        {
            $$ = wj_create_binary_expression(GT_EXPRESSION, $1, $3);
        }
        | relational_expression GE additive_expression
        {
            $$ = wj_create_binary_expression(GE_EXPRESSION, $1, $3);
        }
        | relational_expression LT additive_expression
        {
            $$ = wj_create_binary_expression(LT_EXPRESSION, $1, $3);
        }
        | relational_expression LE additive_expression
        {
            $$ = wj_create_binary_expression(LE_EXPRESSION, $1, $3);
        }
        ;
additive_expression
        : multiplicative_expression
        | additive_expression ADD multiplicative_expression
        {
            $$ = wj_create_binary_expression(ADD_EXPRESSION, $1, $3);
        }
        | additive_expression SUB multiplicative_expression
        {
            $$ = wj_create_binary_expression(SUB_EXPRESSION, $1, $3);
        }
        ;
multiplicative_expression
        : unary_expression
        | multiplicative_expression MUL unary_expression
        {
            $$ = wj_create_binary_expression(MUL_EXPRESSION, $1, $3);
        }
        | multiplicative_expression DIV unary_expression
        {
            $$ = wj_create_binary_expression(DIV_EXPRESSION, $1, $3);
        }
        | multiplicative_expression MOD unary_expression
        {
            $$ = wj_create_binary_expression(MOD_EXPRESSION, $1, $3);
        }
        ;
unary_expression
        : postfix_expression
        | SUB unary_expression
        {
            $$ = wj_create_minus_expression($2);
        }
		| EXCLAMATION unary_expression
		{
			$$ = wj_create_logical_not_expression($2);
		}
        ;
postfix_expression
        : primary_expression
        | postfix_expression LB expression RB
        {
            $$ = wj_create_index_expression($1, $3);
        }
        | postfix_expression DOT IDENTIFIER
        {
            $$ = wj_create_member_expression($1, $3);
        }
		| postfix_expression LP argument_list RP
		{
			$$ = wj_create_function_call_expression($1, $3);
		}
        | postfix_expression LP RP
        {
            $$ = wj_create_function_call_expression($1, NULL);
        }
        | postfix_expression INCREMENT
        {
            $$ = wj_create_incdec_expression($1, INCREMENT_EXPRESSION);
        }
        | postfix_expression DECREMENT
        {
            $$ = wj_create_incdec_expression($1, DECREMENT_EXPRESSION);
        }
        ;
primary_expression
        : LP expression RP
        {
            $$ = $2;
        }
        | IDENTIFIER
        {
            $$ = wj_create_identifier_expression($1);
        }
        | INT_LITERAL
        | DOUBLE_LITERAL
        | STRING_LITERAL
        | TRUE_T
        {
            $$ = wj_create_boolean_expression(WJ_TRUE);
        }
        | FALSE_T
        {
            $$ = wj_create_boolean_expression(WJ_FALSE);
        }
        | NULL_T
        {
            $$ = wj_create_null_expression();
        }
        | array_literal
		| closure_definition
        ;
array_literal
        : LC expression_list RC
        {
            $$ = wj_create_array_expression($2);
        }
        | LC expression_list COMMA RC
        {
            $$ = wj_create_array_expression($2);
        }
        ;
closure_definition
		: CLOSURE IDENTIFIER LP parameter_list RP block
		{
			/* 闭包：标识符（参数列表）{程序块} */
			$$ = wj_create_closure_definition($2, $4, $6);
		}
		| CLOSURE IDENTIFIER LP RP block
		{
			/* 闭包：标识符（）{程序块} */
			$$ = wj_create_closure_definition($2, NULL, $5);
		}
		| CLOSURE LP parameter_list RP block
		{
			/* 闭包：（参数列表）{程序块} */
			$$ = wj_create_closure_definition(NULL, $3, $5);
		}
		| CLOSURE LP RP block
		{
			/* 闭包：（）{程序块} */
			$$ = wj_create_closure_definition(NULL, NULL, $4);
		}
		;
expression_list
        : /* empty */
        {
            $$ = NULL;
        }
        | assignment_expression
        {
            $$ = wj_create_expression_list($1);
        }
        | expression_list COMMA assignment_expression
        {
            $$ = wj_chain_expression_list($1, $3);
        }
        ;
statement
        : expression
        {
          $$ = wj_create_expression_statement($1);
        }
        | global_statement
        | if_statement
        | while_statement
		| foreach_statement
        | return_statement
        | break_statement
        | continue_statement
		| throw_statement
        ;
global_statement
        : GLOBAL_T identifier_list
        {
			/* 全局：标识符1，标识符2，... */
            $$ = wj_create_global_statement($2);
        }
        ;
identifier_list
        : IDENTIFIER
        {
            $$ = wj_create_global_identifier($1);
        }
        | identifier_list COMMA IDENTIFIER
        {
            $$ = wj_chain_identifier($1, $3);
        }
        ;
if_statement
        : IF expression block
        {
			/* 如果：表达式 {...} */
            $$ = wj_create_if_statement($2, $3, NULL, NULL);
        }
        | IF expression block ELSE block
        {
			/* 如果：表达式 {...} 否则 {...} */
            $$ = wj_create_if_statement($2, $3, NULL, $5);
        }
        | IF expression block elsif_list
        {
			/* 如果：表达式 {...} 若是：表达式 {...} 若是：表达式 {...} ... */
            $$ = wj_create_if_statement($2, $3, $4, NULL);
        }
        | IF expression block elsif_list ELSE block
        {
			/* 如果：表达式 {...} 若是：表达式 {...} ... 否则 {...} */
            $$ = wj_create_if_statement($2, $3, $4, $6);
        }
        ;
elsif_list
        : elsif
        | elsif_list elsif
        {
            $$ = wj_chain_elsif_list($1, $2);
        }
        ;
elsif
        : ELSIF expression block
        {
            $$ = wj_create_elsif($2, $3);
        }
        ;
while_statement
        : WHILE expression block
        {
			/* 循环：表达式 {...} */
            $$ = wj_create_while_statement($2, $3);
        }
		| WHILE expression COMMA expression COMMA expression block
		{
			/* 循环：次数=0，次数<10；次数++ {...} */
            $$ = wj_create_for_statement($2, $4, $6, $7);
		}
        ;
foreach_statement
		: FOREACH IDENTIFIER ASSIGN expression block
		{
			/* 逐个：变量 = 数组 {...} */
			$$ = wj_create_foreach_statement(NULL, $2, $4, $5);
		}
		;
return_statement
        : RETURN_T COLON expression /* 有返回值 */
        {
			/* 返回：返回值 */
            $$ = wj_create_return_statement($3);
        }
		| RETURN_T /* 无返回值 */
		{
			/* 返回 */
            $$ = wj_create_return_statement(NULL);
		}
        ;
break_statement
        : BREAK
        {
            $$ = wj_create_break_statement();
        }
        ;
continue_statement
        : CONTINUE
        {
            $$ = wj_create_continue_statement();
        }
        ;
throw_statement
		: THROW expression
		{
			$$ = wj_create_throw_statement($2);
		}
block
        : LC statement_list RC
        {
            $$ = wj_create_block($2);
        }
        | LC RC
        {
            $$ = wj_create_block(NULL);
        }
        ;
%%
